﻿Imports SFDL.Core
Imports SFDL.File
Imports System.Xml
Imports System.Threading
Imports System.Net.FtpClient
Imports SFDL.LoaderExtensions
Imports System.IO
Imports System.Net
Imports System.Text
Imports System.Threading.Tasks
Imports SFDL.Crypto
Imports SFDL.LegacyFile
Imports SFDL.LegacyFile.SFDL.FTP
Imports SFDL.Logging

Module OpenSFDLHelper

    Const MAXSFDLFILEVERSION As Integer = 9
    Const LEGACYSFDLFILEVERSION As Integer = 5
    Private _log As NLog.Logger = NLog.LogManager.GetLogger("OpenSFDLHelper")

#Region "SFDL Datei öffnen"

    Friend Sub OpenSFDLFiles(ByVal _sfdl_file_path_list() As String, ByVal _taskid As Guid)

        For Each _sfdl_file_path In _sfdl_file_path_list

            Dim _tools As New Tools

            Dim _sfdl_file As New SFDLFile
            Dim _legacy_sfdl_file As New SFDL_File
            Dim _sfdl_file_version As Integer
            Dim _decrypt_password As String = String.Empty
            Dim _legacy_mode As Boolean = False

            Dim _sfdl_file_uid As String = String.Empty
            Dim _sfdl_session As New SFDLSession
            Dim _olv_file_item_list As New List(Of OLV_Item)

            Dim _bulk_package_found As Boolean = False
            Dim _bulk_package_list As New List(Of SFDLPackage)

            Dim _countrycode As String = String.Empty
            Dim _flag As Image = My.Resources.question

            Try

                'Prüfen ob die SFDL Container Version kompatibel ist

                _sfdl_file_version = GetSFDLFileVersion(_sfdl_file_path)

                If _sfdl_file_version > MAXSFDLFILEVERSION Then
                    Throw New Exception("Die SFDL Loader ist nicht kompatibel zu dieser SFDL Datei. Bitte lade dir die aktuellste Version herunter!")
                End If

                'Legacy SFDL verarbeiten

                If _sfdl_file_version <= LEGACYSFDLFILEVERSION Then

                    _log.Info("Legacy SFDL Ermittelt")

                    _legacy_mode = True

                    _legacy_sfdl_file = CType(_tools.XMLDeSerialize(_legacy_sfdl_file, _sfdl_file_path), SFDL_File)

                    If _legacy_sfdl_file.GetSetEncryptet = True Then

                        frm_opensfdl_encrypted.TopMost = True
                        frm_opensfdl_encrypted.SetTestDecryptString = _legacy_sfdl_file.GetSetConnectionInfo.GetSetHost
                        frm_opensfdl_encrypted.SetSFDLFileName = Path.GetFileNameWithoutExtension(_sfdl_file_path)

                        If frm_opensfdl_encrypted.ShowDialog() = DialogResult.OK Then
                            _decrypt_password = frm_opensfdl_encrypted.GetPassword
                            frm_opensfdl_encrypted.Dispose()
                        Else
                            Throw New UserCancelException
                        End If

                        _legacy_sfdl_file = DecryptLegacyFile(_legacy_sfdl_file, _decrypt_password)

                    End If

                    If String.IsNullOrWhiteSpace(_legacy_sfdl_file.GetSetDescription) Then
                        _legacy_sfdl_file.GetSetDescription = Path.GetFileNameWithoutExtension(_sfdl_file_path)
                    End If

                Else 'Normale Aktuelle SFDL Datei verarbeiten

                    _sfdl_file = CType(_tools.XMLDeSerialize(_sfdl_file, _sfdl_file_path), SFDLFile)

                    If _sfdl_file.Encrypted = True Then

                        frm_opensfdl_encrypted.TopMost = True
                        frm_opensfdl_encrypted.SetTestDecryptString = _sfdl_file.ConnectionInfo.Host
                        frm_opensfdl_encrypted.SetSFDLFileName = Path.GetFileNameWithoutExtension(_sfdl_file_path)

                        If Not frm_opensfdl_encrypted.ShowDialog() >= DialogResult.Cancel Then
                            _decrypt_password = frm_opensfdl_encrypted.GetPassword
                            frm_opensfdl_encrypted.Dispose()
                        Else
                            Throw New UserCancelException
                        End If

                        _sfdl_file = DecryptFile(_sfdl_file, _decrypt_password)

                    End If

                    If String.IsNullOrWhiteSpace(_sfdl_file.Description) Then
                        _sfdl_file.Description = Path.GetFileNameWithoutExtension(_sfdl_file_path)
                    End If

                End If

                'Legacy SFDL File in neues Format konvertieren
                If _legacy_mode = True Then
                    _sfdl_file = ConvertLegacyFile(_legacy_sfdl_file)
                End If

                _sfdl_file_uid = _tools.GenerateSFDLFileUID(_sfdl_file)

                If GetSFDLSessionList.ContainsKey(_sfdl_file_uid) = True Then
                    Throw New Exception("Die SFDL Datei ist bereits geladen!")
                End If

                With _sfdl_session

                    .SessionState = SFDLSessionEnums.SFDLSessionState.Queued
                    .SFDLFile = _sfdl_file
                    .SFDLSessionName = _sfdl_file_uid
                    .SFDLFileName = Path.GetFileNameWithoutExtension(_sfdl_file_path)

                End With

                For Each _package In _sfdl_file.Packages

                    If _package.BulkFolderMode = False Then

                        For Each _file In _package.FileList

                            Dim _olv_file_item As New OLV_Item

                            With _olv_file_item

                                .DirectoryPath = _file.DirectoryPath
                                .DirectoryRoot = _file.DirectoryRoot
                                .FileFullPath = _file.FileFullPath
                                .FileName = _file.FileName
                                .FileSize = _file.FileSize
                                .FileHashType = _file.FileHashType
                                .FileHash = _file.FileHash
                                .PackageName = _file.PackageName
                                .Progress = 0
                                .Status = Status.Queued
                                .SFDLSessionName = _sfdl_file_uid
                                .GroupSortIndicator = GetSFDLSessionList.Count + 1 & ";" & _package.Packagename & ";" & _sfdl_session.SFDLSessionName

                            End With

                            _olv_file_item_list.Add(_olv_file_item)

                        Next

                    Else
                        _bulk_package_found = True
                        _bulk_package_list.Add(_package)
                    End If

                Next

                For Each _bulk_package In _bulk_package_list

                    Dim _result_list As New List(Of OLV_Item)

                    Dim _t1 As Task(Of List(Of OLV_Item)) = Task.Factory.StartNew(Function() GetBulkFileList(_bulk_package, _sfdl_file.ConnectionInfo, _sfdl_session.SFDLSessionName, _taskid))

                    _result_list = _t1.Result

                    If IsNothing(_result_list) Or _result_list.Count = 0 Then
                        Throw New Exception("Bulk File List konnte nicht ermittelt werden!")
                    End If

                    For Each _olv_item As OLV_Item In _result_list

                        Dim _item As New File.FileInfo

                        With _item

                            .DirectoryPath = _olv_item.DirectoryPath
                            .DirectoryRoot = _olv_item.DirectoryRoot
                            .FileFullPath = _olv_item.FileFullPath
                            .FileName = _olv_item.FileName
                            .FileSize = _olv_item.FileSize
                            .FileHash = _olv_item.FileHash
                            .FileHashType = _olv_item.FileHashType
                            .PackageName = _olv_item.PackageName

                        End With

                        _bulk_package.FileList.Add(_item)

                    Next

                    _olv_file_item_list.AddRange(_t1.Result)

                    _bulk_package.BulkFolderList = Nothing
                    _bulk_package.BulkFolderMode = False

                Next

                For Each _olv_item In _olv_file_item_list
                    UpdateItemSizeSpeedCollection(_olv_item)
                Next

                _sfdl_session.OLVItemList = _olv_file_item_list

                AddSFDLSession(New KeyValuePair(Of String, SFDLSession)(_sfdl_session.SFDLSessionName, _sfdl_session))

                Task.Factory.StartNew(Sub()

                                          frm_main.OLV_Download_Items.AddObjects(_sfdl_session.OLVItemList)

                                          If GetSettings.MarkAllContainerFiles = True Then
                                              frm_main.OLV_Download_Items.CheckObjects(_sfdl_session.OLVItemList)
                                          End If

                                      End Sub, New CancellationToken, TaskCreationOptions.PreferFairness, GetRootUIContext).ContinueWith(Sub()

                                                                                                                                             Parallel.ForEach(_sfdl_session.OLVItemList, Sub(_olv_item)

                                                                                                                                                                                             Dim _download_file_path As String = String.Empty
                                                                                                                                                                                             Dim _file_info As IO.FileInfo

                                                                                                                                                                                             _download_file_path = GetDownloadFilePath(GetSettings, _sfdl_session, _olv_item)

                                                                                                                                                                                             If Not String.IsNullOrWhiteSpace(_download_file_path) Then

                                                                                                                                                                                                 _file_info = New IO.FileInfo(_download_file_path)

                                                                                                                                                                                                 If IO.File.Exists(_download_file_path) = True Then

                                                                                                                                                                                                     _log.Info("Datei {0} existiert!", _olv_item.FileName)

                                                                                                                                                                                                     If Not _olv_item.FileSize = 0 Then

                                                                                                                                                                                                         _log.Info("Prüfe Dateigröße von Datei {0}", _olv_item.FileName)

                                                                                                                                                                                                         If _file_info.Length.Equals(_olv_item.FileSize) Then

                                                                                                                                                                                                             _log.Info("Dateigrösse entpricht angabe in SFDL File - Markiere Datei als heruntergeladen.")
                                                                                                                                                                                                             UpdateItem(_olv_item, UpdateItemEventType.FileAlreadyDownloaded)
                                                                                                                                                                                                         Else

                                                                                                                                                                                                             _log.Warn("Dateigrösse entpricht NICHT der angabe im SFDL File")
                                                                                                                                                                                                         End If

                                                                                                                                                                                                     Else
                                                                                                                                                                                                         _log.Warn("Dateigrösse in SFDL File nicht vorhanden - Überspringe prüfung")

                                                                                                                                                                                                     End If

                                                                                                                                                                                                 End If

                                                                                                                                                                                             End If

                                                                                                                                                                                         End Sub)

                                                                                                                                             Try

                                                                                                                                                 Dim _whois As New WhoisResolver

                                                                                                                                                 _countrycode = _whois.Resolve(_sfdl_session.SFDLFile.ConnectionInfo.Host)
                                                                                                                                                 _flag = _whois.DownloadFlagImage(_countrycode)

                                                                                                                                             Catch ex As Exception
                                                                                                                                                 _log.Warn(ex, "WhoIs fehlgeschlagen")
                                                                                                                                             End Try

                                                                                                                                         End Sub, New CancellationToken, TaskContinuationOptions.NotOnFaulted).ContinueWith(Sub()

                                                                                                                                                                                                                                Dim _item As ToolStripItem

                                                                                                                                                                                                                                frm_main.OLV_Download_Items.ShowGroups = True

                                                                                                                                                                                                                                frm_main.OLV_Download_Items.BuildGroups(frm_main.olvc_groupsort, SortOrder.None)

                                                                                                                                                                                                                                frm_main.tss_serverinfo.Visible = True

                                                                                                                                                                                                                                If Not String.IsNullOrEmpty(_countrycode) Then
                                                                                                                                                                                                                                    _item = frm_main.tss_serverinfo.DropDownItems.Add(_sfdl_session.SFDLFile.Description & " / Land: " & _countrycode)
                                                                                                                                                                                                                                    _item.Image = _flag
                                                                                                                                                                                                                                    _item.Name = _sfdl_session.SFDLSessionName
                                                                                                                                                                                                                                Else
                                                                                                                                                                                                                                    _item = frm_main.tss_serverinfo.DropDownItems.Add(_sfdl_session.SFDLFile.Description & " / Land: N/A")
                                                                                                                                                                                                                                    _item.Image = My.Resources.question
                                                                                                                                                                                                                                    _item.Name = _sfdl_session.SFDLSessionName

                                                                                                                                                                                                                                End If

                                                                                                                                                                                                                            End Sub, New CancellationToken, TaskContinuationOptions.NotOnFaulted, GetRootUIContext)

            Catch ex As Exception

                Dim _error_text As New StringBuilder

                _log.Error(ex, ex.Message)

                _error_text.AppendLine(ex.Message)

                If Not IsNothing(ex.InnerException) Then
                    _error_text.AppendLine(ex.InnerException.Message)
                End If

                MessageBox.Show("Fehler beim Öffnen der SFDL Dateie(n)" & vbNewLine & "Fehlermeldung: " & _error_text.ToString, "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error)

            End Try

        Next

    End Sub

    Private Function GetSFDLFileVersion(ByVal _filename As String) As Integer

        Dim _xml As New XmlDocument
        Dim _version As Integer

        _xml.LoadXml(My.Computer.FileSystem.ReadAllText(_filename, Encoding.Default))

        Try
            'Zuerst prüfen ob es sich um eine alte SFDL Version handelt

            For Each _element As XmlNode In _xml.GetElementsByTagName("GetSetFileVersion")
                _version = Integer.Parse(_element.InnerText.ToString)
            Next

            For Each _element As XmlNode In _xml.GetElementsByTagName("SFDLFileVersion")
                _version = Integer.Parse(_element.InnerText.ToString)
            Next

        Catch ex As Exception
            _version = 0
        End Try

        _log.Info("SFDL File Version: {0}", _version)

        Return _version

    End Function

    Private Function DecryptFile(ByVal _sfdl_file As SFDLFile, ByVal _password As String) As SFDLFile

        Dim _decrypted_sfdl_file As New SFDLFile
        Dim _crypto As New AES

        _decrypted_sfdl_file.Packages = New List(Of SFDLPackage)

        With _decrypted_sfdl_file

            .Description = _crypto.DecryptString(_sfdl_file.Description, _password)
            .Uploader = _crypto.DecryptString(_sfdl_file.Uploader, _password)
            .Encrypted = False
            .MaxDownloadThreads = _sfdl_file.MaxDownloadThreads
            .SFDLFileVersion = _sfdl_file.SFDLFileVersion

        End With

        With _decrypted_sfdl_file.ConnectionInfo

            .AuthRequired = _sfdl_file.ConnectionInfo.AuthRequired
            .CharacterEncoding = _sfdl_file.ConnectionInfo.CharacterEncoding
            .DataConnectionType = _sfdl_file.ConnectionInfo.DataConnectionType
            .DataType = _sfdl_file.ConnectionInfo.DataType
            .DefaultPath = _crypto.DecryptString(_sfdl_file.ConnectionInfo.DefaultPath, _password)
            .EncryptionMode = _sfdl_file.ConnectionInfo.EncryptionMode
            .Host = _crypto.DecryptString(_sfdl_file.ConnectionInfo.Host, _password)
            .ListMethod = _sfdl_file.ConnectionInfo.ListMethod
            .Password = _crypto.DecryptString(_sfdl_file.ConnectionInfo.Password, _password)
            .Port = _sfdl_file.ConnectionInfo.Port
            .Username = _crypto.DecryptString(_sfdl_file.ConnectionInfo.Username, _password)
            .ForceSingleConnection = _sfdl_file.ConnectionInfo.ForceSingleConnection

        End With

        For Each _package In _sfdl_file.Packages

            Dim _decrypted_package As New SFDLPackage

            With _decrypted_package

                .Packagename = _crypto.DecryptString(_package.Packagename, _password)
                .BulkFolderMode = _package.BulkFolderMode
                .FileList = New List(Of File.FileInfo)
                .BulkFolderList = New List(Of BulkFolder)

            End With

            For Each _file In _package.FileList

                Dim _decrypted_file As New File.FileInfo

                With _decrypted_file

                    .DirectoryPath = _crypto.DecryptString(_file.DirectoryPath, _password)
                    .DirectoryRoot = _crypto.DecryptString(_file.DirectoryRoot, _password)
                    .FileFullPath = _crypto.DecryptString(_file.FileFullPath, _password)
                    .FileHash = _file.FileHash
                    .FileHashType = _file.FileHashType
                    .FileName = _crypto.DecryptString(_file.FileName, _password)
                    .FileSize = _file.FileSize
                    .PackageName = _crypto.DecryptString(_file.PackageName, _password)

                End With

                _decrypted_package.FileList.Add(_decrypted_file)

            Next

            For Each _bulk_folder In _package.BulkFolderList

                Dim _decrypted_bulk_folder As New BulkFolder

                With _decrypted_bulk_folder

                    .BulkFolderPath = _crypto.DecryptString(_bulk_folder.BulkFolderPath, _password)
                    .PackageName = _crypto.DecryptString(_bulk_folder.PackageName, _password)

                End With

                _decrypted_package.BulkFolderList.Add(_decrypted_bulk_folder)

            Next

            _decrypted_sfdl_file.Packages.Add(_decrypted_package)

        Next

        Return _decrypted_sfdl_file

    End Function

    Private Function DecryptLegacyFile(ByVal _legacy_sfdl_file As SFDL_File, ByVal _password As String) As SFDL_File

        Dim _rt_sfdl_file As New SFDL_File
        Dim _rt_file_list As New List(Of LegacyFile.FileInfo)
        Dim _crypto As New AES

        _rt_sfdl_file.GetSetDescription = _crypto.DecryptString(_legacy_sfdl_file.GetSetDescription, _password)
        _rt_sfdl_file.GetsetUploader = _crypto.DecryptString(_legacy_sfdl_file.GetsetUploader, _password)

        _rt_sfdl_file.GetSetFileVersion = _legacy_sfdl_file.GetSetFileVersion
        _rt_sfdl_file.GetSetMaxDownloadThread = _legacy_sfdl_file.GetSetMaxDownloadThread

        For Each _file_info In _legacy_sfdl_file.GetSetFileInfoList

            Dim _rt_legacy_file_info As New LegacyFile.FileInfo

            _rt_legacy_file_info.GetSetDirectoryPath = _crypto.DecryptString(_file_info.GetSetDirectoryPath, _password)
            _rt_legacy_file_info.GetSetDirectoryRoot = _crypto.DecryptString(_file_info.GetSetDirectoryRoot, _password)
            _rt_legacy_file_info.GetSetFileFullPath = _crypto.DecryptString(_file_info.GetSetFileFullPath, _password)
            _rt_legacy_file_info.GetSetFileName = _crypto.DecryptString(_file_info.GetSetFileName, _password)
            _rt_legacy_file_info.GetSetMD5FileHash = _crypto.DecryptString(_file_info.GetSetMD5FileHash, _password)

            _rt_legacy_file_info.GetSetFileSize = _file_info.GetSetFileSize

            _rt_file_list.Add(_rt_legacy_file_info)

        Next

        _rt_sfdl_file.GetSetFileInfoList = _rt_file_list

        _rt_sfdl_file.GetSetConnectionInfo.GetSetHost = _crypto.DecryptString(_legacy_sfdl_file.GetSetConnectionInfo.GetSetHost, _password)
        _rt_sfdl_file.GetSetConnectionInfo.GetSetName = _crypto.DecryptString(_legacy_sfdl_file.GetSetConnectionInfo.GetSetName, _password)
        _rt_sfdl_file.GetSetConnectionInfo.GetSetPassword = _crypto.DecryptString(_legacy_sfdl_file.GetSetConnectionInfo.GetSetPassword, _password)
        _rt_sfdl_file.GetSetConnectionInfo.GetSetPath = _crypto.DecryptString(_legacy_sfdl_file.GetSetConnectionInfo.GetSetPath, _password)
        _rt_sfdl_file.GetSetConnectionInfo.GetSetUsername = _crypto.DecryptString(_legacy_sfdl_file.GetSetConnectionInfo.GetSetUsername, _password)

        _rt_sfdl_file.GetSetConnectionInfo.GetSetPort = _legacy_sfdl_file.GetSetConnectionInfo.GetSetPort
        _rt_sfdl_file.GetSetConnectionInfo.GetSetSecurityProtocol = _legacy_sfdl_file.GetSetConnectionInfo.GetSetSecurityProtocol
        _rt_sfdl_file.GetSetConnectionInfo.GetSetTransferMode = _legacy_sfdl_file.GetSetConnectionInfo.GetSetTransferMode
        _rt_sfdl_file.GetSetConnectionInfo.GetSetTransferType = _legacy_sfdl_file.GetSetConnectionInfo.GetSetTransferType
        _rt_sfdl_file.GetSetConnectionInfo.GetSetAuthRequired = _legacy_sfdl_file.GetSetConnectionInfo.GetSetAuthRequired
        _rt_sfdl_file.GetSetConnectionInfo.GetSetCharacterEncoding = _legacy_sfdl_file.GetSetConnectionInfo.GetSetCharacterEncoding
        _rt_sfdl_file.GetSetConnectionInfo.GetSetUseSpecialCharacterFix = _rt_sfdl_file.GetSetConnectionInfo.GetSetUseSpecialCharacterFix

        Return _rt_sfdl_file

    End Function

    Private Function ConvertLegacyFile(ByVal _legacy_file As SFDL_File) As SFDLFile

        Dim _sfdl_file As New SFDLFile
        Dim _file_list As New List(Of File.FileInfo)
        Dim _package As New SFDLPackage

        _sfdl_file.Uploader = _legacy_file.GetsetUploader
        _sfdl_file.Description = _legacy_file.GetSetDescription
        _sfdl_file.MaxDownloadThreads = _legacy_file.GetSetMaxDownloadThread
        _sfdl_file.SFDLFileVersion = MAXSFDLFILEVERSION

        With _sfdl_file.ConnectionInfo

            .AuthRequired = _legacy_file.GetSetConnectionInfo.GetSetAuthRequired
            .CharacterEncoding = CType(_legacy_file.GetSetConnectionInfo.GetSetCharacterEncoding, CharacterEncoding.CharacterEncoding)

            If _legacy_file.GetSetConnectionInfo.GetSetTransferType = FTP.TransferType.Ascii Then
                .DataType = FtpDataType.ASCII
            Else
                .DataType = FtpDataType.Binary
            End If

            If _legacy_file.GetSetConnectionInfo.GetSetTransferMode = FTP.TransferMode.Active Then
                .DataConnectionType = FtpDataConnectionType.AutoActive
            Else
                .DataConnectionType = FtpDataConnectionType.PASV
            End If

            .Host = _legacy_file.GetSetConnectionInfo.GetSetHost
            .Password = _legacy_file.GetSetConnectionInfo.GetSetPassword
            .Port = _legacy_file.GetSetConnectionInfo.GetSetPort
            .EncryptionMode = FtpEncryptionMode.None
            .Username = _legacy_file.GetSetConnectionInfo.GetSetUsername

            .ForceSingleConnection = False

        End With

        For Each _legacy_file_info In _legacy_file.GetSetFileInfoList

            Dim _file As New File.FileInfo

            _file.DirectoryPath = _legacy_file_info.GetSetDirectoryPath
            _file.DirectoryRoot = _legacy_file_info.GetSetDirectoryRoot
            _file.FileFullPath = _legacy_file_info.GetSetFileFullPath
            _file.FileName = _legacy_file_info.GetSetFileName
            _file.FileSize = _legacy_file_info.GetSetFileSize

            If String.IsNullOrEmpty(_legacy_file_info.GetSetMD5FileHash) Then
                _file.FileHashType = File.FileInfo.HashType.None
                _file.FileHash = String.Empty
            Else
                _file.FileHash = _legacy_file_info.GetSetMD5FileHash
                _file.FileHashType = File.FileInfo.HashType.MD5
            End If

            _file.PackageName = "Legacy Package"

            _file_list.Add(_file)

        Next

        _package.FileList = _file_list
        _package.Packagename = "Legacy Package"

        _sfdl_file.Packages.Add(_package)

        _sfdl_file.Encrypted = False

        Return _sfdl_file

    End Function

    Private Function GetBulkFileList(ByVal _package As SFDLPackage, ByVal _sdfl_connection_info As File.ConnectionInfo, ByVal _session_name As String, ByVal _taskid As Guid) As List(Of OLV_Item)

        Dim _ftp_client As New FtpClient
        Dim _rt As New List(Of OLV_Item)
        Dim _tools As New Tools

        With _ftp_client

            If _sdfl_connection_info.AuthRequired Then
                .Credentials = New NetworkCredential(_sdfl_connection_info.Username, _sdfl_connection_info.Password)
            Else
                .Credentials = New NetworkCredential("anonymous", "anonymous@sfdl.net")
            End If

            .DataConnectionType = _sdfl_connection_info.DataConnectionType
            .EncryptionMode = _sdfl_connection_info.EncryptionMode
            .Host = _sdfl_connection_info.Host
            .Port = _sdfl_connection_info.Port
            .Encoding = _tools.ConvertCharacterEncoding(_sdfl_connection_info.CharacterEncoding)

            If _sdfl_connection_info.ForceSingleConnection = True Then
                _log.Info("Erzwinge Einzelverbindung!")
                .EnableThreadSafeDataConnections = False
            End If

            If _sdfl_connection_info.SpecialServerMode = True Then
                .EnableThreadSafeDataConnections = False
                .SpecialServerMode = True
                .StaleDataCheck = False
            End If

            If Not .EncryptionMode = FtpEncryptionMode.None Then 'FTPS Workaround
                .DataConnectionEncryption = False
            End If

            .NoPathAppend = True

        End With

        AddHandler _ftp_client.ValidateCertificate, AddressOf ValidateCertificateEvent

        _ftp_client.Connect()

        For Each _bulk_folder In _package.BulkFolderList
            _rt = GetListing(_bulk_folder.BulkFolderPath, _ftp_client, _session_name, _bulk_folder, _sdfl_connection_info.ListMethod)
        Next

        _ftp_client.Disconnect()

        Return _rt

    End Function

    Private Function GetListing(ByVal _path As String, ByVal _ftp_client As FtpClient, ByVal _sfdl_session_name As String, ByVal _bulk_folder As BulkFolder, ByVal _list_method As FtpListOption) As List(Of OLV_Item)

        Dim _olv_file_list As New List(Of OLV_Item)

        Try

            _ftp_client.SetWorkingDirectory(_path)

            For Each _item As FtpListItem In _ftp_client.GetListing("", _list_method)

                If _item.Type = FtpFileSystemObjectType.Directory Then
                    GetListing(_item.FullName, _ftp_client, _sfdl_session_name, _bulk_folder, _list_method)
                Else

                    If _item.Type = FtpFileSystemObjectType.File Then

                        _log.Debug("Dateiname : {0}", _item.Name)
                        _log.Debug("Dateipfad: {0}", _item.FullName)

                        Dim _olv_item As New OLV_Item

                        With _olv_item

                            ' .DirectoryRoot = _bulk_folder.BulkFolderPath
                            .DirectoryPath = Path.GetDirectoryName(_item.FullName)
                            .FileFullPath = _item.FullName
                            .FileName = _item.Name
                            .FileSize = _item.Size
                            .Progress = 0
                            .SizeDownloaded = 0
                            .PackageName = _bulk_folder.PackageName
                            .Status = Status.Queued
                            .StatusText = String.Empty
                            .DownloadSpeed = String.Empty
                            .FileHash = String.Empty
                            .FileHashType = File.FileInfo.HashType.None
                            .SFDLSessionName = _sfdl_session_name
                            .GroupSortIndicator = GetSFDLSessionList.Count + 1 & ";" & .PackageName & ";" & _sfdl_session_name

                        End With

                        _olv_file_list.Add(_olv_item)

                    End If

                End If

            Next

            'ToDo/Bugfix: Auf unterornder einlesen

        Catch ex As Exception
            _log.Error(ex, ex.Message)
        End Try

        Return _olv_file_list

    End Function

    Private Sub ValidateCertificateEvent(control As FtpClient, e As FtpSslValidationEventArgs)
        e.Accept = True
    End Sub

#End Region

#Region "SFDL Session öffnen/wiederherstellen"

    Friend Sub OpenSFDLSessions(ByVal _session_file_list() As String, ByVal _taskid As Guid)

        For Each _session_file_path In _session_file_list

            Dim _sfdl_session As New SFDLSession
            Dim _tools As New Tools

            Dim _whois As New WhoisResolver
            Dim _countrycode As String = String.Empty
            Dim _flag As Image = My.Resources.question
            Dim _tss_item As ToolStripItem

            _sfdl_session = CType(_tools.XMLDeSerialize(_sfdl_session, _session_file_path), SFDLSession)

            _sfdl_session.SessionState = SFDLSessionEnums.SFDLSessionState.Queued

            For Each _olv_item In _sfdl_session.OLVItemList
                UpdateItemSizeSpeedCollection(_olv_item)
            Next

            AddSFDLSession(New KeyValuePair(Of String, SFDLSession)(_sfdl_session.SFDLSessionName, _sfdl_session))

            Task.Factory.StartNew(Sub()

                                      frm_main.OLV_Download_Items.AddObjects(_sfdl_session.OLVItemList)

                                      Parallel.ForEach(_sfdl_session.OLVItemList, Sub(_olv_item As OLV_Item)

                                                                                      Dim _download_file_path As String = String.Empty
                                                                                      Dim _file_info As IO.FileInfo

                                                                                      If _sfdl_session.SavedCheckedItems.Where(Function(_item As OLV_Item) _item.FileFullPath = _olv_item.FileFullPath).Count = 1 Then
                                                                                          _olv_item.Checked = True
                                                                                      End If

                                                                                      _download_file_path = GetDownloadFilePath(GetSettings, _sfdl_session, _olv_item)

                                                                                      _file_info = New IO.FileInfo(_download_file_path)

                                                                                      If IO.File.Exists(_download_file_path) = True Then


                                                                                          _log.Info("Datei {0} existiert!", _olv_item.FileName)

                                                                                          If Not _olv_item.FileSize = 0 Then

                                                                                              _log.Info("Prüfe Dateigrösse der Datei {0}....", _olv_item.FileName)


                                                                                              If _file_info.Length.Equals(_olv_item.FileSize) Then

                                                                                                  _log.Info("Dateigrösse entpricht angabe in SFDL File - Markiere Datei als heruntergeladen.")
                                                                                                  UpdateItem(_olv_item, UpdateItemEventType.FileAlreadyDownloaded)
                                                                                              Else

                                                                                                  _log.Warn("Dateigrösse entpricht NICHT der angabe im SFDL File")
                                                                                              End If

                                                                                          Else

                                                                                              _log.Warn("Dateigrösse in SFDL File nicht vorhanden - Überspringe prüfung")
                                                                                          End If

                                                                                      End If

                                                                                  End Sub)

                                      frm_main.OLV_Download_Items.ShowGroups = True

                                      frm_main.OLV_Download_Items.BuildGroups(frm_main.olvc_groupsort, SortOrder.None)

                                      Try

                                          _countrycode = _whois.Resolve(_sfdl_session.SFDLFile.ConnectionInfo.Host)
                                          _flag = _whois.DownloadFlagImage(_countrycode)

                                      Catch ex As Exception
                                          _log.Warn(ex, "WhoIs Fehlgeschlagen!")
                                      End Try

                                      frm_main.tss_serverinfo.Visible = True

                                      If Not String.IsNullOrEmpty(_countrycode) Then
                                          _tss_item = frm_main.tss_serverinfo.DropDownItems.Add(_sfdl_session.SFDLFile.Description & " / Land: " & _countrycode)
                                          _tss_item.Image = _flag
                                          _tss_item.Name = _sfdl_session.SFDLSessionName
                                      Else
                                          _tss_item = frm_main.tss_serverinfo.DropDownItems.Add(_sfdl_session.SFDLFile.Description & " / Land: N/A")
                                          _tss_item.Image = My.Resources.question
                                          _tss_item.Name = _sfdl_session.SFDLSessionName

                                      End If

                                  End Sub, New CancellationToken, TaskCreationOptions.AttachedToParent, GetRootUIContext)

        Next

    End Sub

#End Region

End Module